/**
 * @file trade_engine.h
 * @brief 交易引擎的头文件定义
 * 
 * @details 该文件定义了交易引擎（TradeEngine）类，它是交易系统的核心组件，
 * 负责处理市场数据更新、订单更新，并根据交易算法生成交易决策。
 * 交易引擎连接了市场数据、订单管理、风险管理和交易算法等多个组件，
 * 协调它们的工作以实现自动化交易。
 * 
 * @author 原作者
 * @date 2023
 */

#pragma once

#include <functional>

#include "common/thread_utils.h"
#include "common/time_utils.h"
#include "common/lf_queue.h"
#include "common/macros.h"
#include "common/logging.h"

#include "exchange/order_server/client_request.h"
#include "exchange/order_server/client_response.h"
#include "exchange/market_data/market_update.h"

#include "market_order_book.h"

#include "feature_engine.h"
#include "position_keeper.h"
#include "order_manager.h"
#include "risk_manager.h"

#include "market_maker.h"
#include "liquidity_taker.h"

/**
 * @namespace Trading
 * @brief 交易相关的命名空间
 * 
 * @details 该命名空间包含了交易系统的核心组件，如交易引擎、订单管理器、
 * 风险管理器、仓位管理器等。这些组件协同工作，实现自动化交易策略。
 */
namespace Trading {
  /**
   * @class TradeEngine
   * @brief 交易引擎类，交易系统的核心组件
   * 
   * @details 交易引擎负责协调市场数据处理、订单管理、风险控制和交易策略执行。
   * 它维护一个独立的线程，不断处理来自交易所的市场数据和订单响应，
   * 并根据配置的交易算法（做市商或流动性接受者）生成交易决策。
   * 交易引擎使用回调函数机制将市场事件分发给相应的处理组件。
   */
  class TradeEngine {
  public:
    /**
     * @brief 交易引擎的构造函数
     * 
     * @details 初始化交易引擎，设置客户端标识符、算法类型和相关组件。
     * 根据算法类型创建相应的交易算法实例（做市商或流动性接受者），
     * 并初始化所有交易工具的订单簿。
     * 
     * @param client_id 客户端标识符，用于标识交易引擎实例
     * @param algo_type 算法类型，指定使用做市商或流动性接受者算法
     * @param ticker_cfg 交易工具配置映射，包含每个交易工具的配置信息
     * @param client_requests 客户端请求队列指针，用于发送订单请求
     * @param client_responses 客户端响应队列指针，用于接收订单响应
     * @param market_updates 市场数据更新队列指针，用于接收市场数据更新
     */
    TradeEngine(Common::ClientId client_id,
                AlgoType algo_type,
                const TradeEngineCfgHashMap &ticker_cfg,
                Exchange::ClientRequestLFQueue *client_requests,
                Exchange::ClientResponseLFQueue *client_responses,
                Exchange::MEMarketUpdateLFQueue *market_updates);

    /**
     * @brief 交易引擎的析构函数
     * 
     * @details 清理交易引擎分配的资源，包括停止交易线程、
     * 释放交易算法实例和订单簿对象，并重置指针。
     * 在析构前会等待一定时间，确保线程安全终止。
     */
    ~TradeEngine();

    /**
     * @brief 启动交易引擎的主线程
     * 
     * @details 创建并启动交易引擎的主线程，该线程将执行交易引擎的主循环函数。
     * 在启动前将运行标志设置为真，并使用断言确保线程创建成功。
     * 
     * @return void
     */
    auto start() -> void {
      run_ = true;
      ASSERT(Common::createAndStartThread(-1, "Trading/TradeEngine", [this] { run(); }) != nullptr, "Failed to start TradeEngine thread.");
    }

    /**
     * @brief 停止交易引擎的主线程
     * 
     * @details 安全地停止交易引擎的主线程。在停止前，会等待所有未处理的订单响应
     * 和市场数据更新被消费完毕，确保不会丢失重要的交易信息。
     * 在停止前还会记录当前的仓位状态，然后将运行标志设置为假。
     * 
     * @return void
     */
    auto stop() -> void {
      while(incoming_ogw_responses_->size() || incoming_md_updates_->size()) {
        logger_.log("%:% %() % Sleeping till all updates are consumed ogw-size:% md-size:%\n", __FILE__, __LINE__, __FUNCTION__,
                    Common::getCurrentTimeStr(&time_str_), incoming_ogw_responses_->size(), incoming_md_updates_->size());

        using namespace std::literals::chrono_literals;
        std::this_thread::sleep_for(10ms);
      }

      logger_.log("%:% %() % POSITIONS\n%\n", __FILE__, __LINE__, __FUNCTION__, Common::getCurrentTimeStr(&time_str_),
                  position_keeper_.toString());

      run_ = false;
    }

    /**
     * @brief 交易引擎的主循环函数
     * 
     * @details 交易引擎线程的主循环，不断处理来自交易所的订单响应和市场数据更新。
     * 对于每个订单响应，调用onOrderUpdate方法处理；对于每个市场数据更新，
     * 将其分发给相应的订单簿对象处理。这些处理过程可能会生成新的客户端请求。
     * 当run_标志为假时，循环结束。
     * 
     * @return void
     */
    auto run() noexcept -> void;

    /**
     * @brief 将客户端请求写入无锁队列
     * 
     * @details 将交易请求（如下单、撤单等）写入无锁队列，由订单服务器消费并发送给交易所。
     * 这是交易算法向交易所发送订单的主要方式。方法会记录日志并测量写入时间。
     * 
     * @param client_request 要发送的客户端请求指针
     * @return void
     */
    auto sendClientRequest(const Exchange::MEClientRequest *client_request) noexcept -> void;

    /**
     * @brief 处理订单簿变化
     * 
     * @details 处理订单簿的变化，更新仓位管理器和特征引擎，并通知交易算法关于该更新。
     * 这个方法在订单簿中的价格或数量发生变化时被调用，包括新订单的加入和现有订单的取消。
     * 它将更新当前的最优价格（BBO）并调用相应的回调函数。
     * 
     * @param ticker_id 证券标识符
     * @param price 变化的价格
     * @param side 变化的侧向（买入或卖出）
     * @param book 变化的订单簿指针
     * @return void
     */
    auto onOrderBookUpdate(TickerId ticker_id, Price price, Side side, MarketOrderBook *book) noexcept -> void;

    /**
     * @brief 处理成交事件
     * 
     * @details 处理市场上的成交事件，更新特征引擎并通知交易算法关于该成交事件。
     * 当市场上发生成交时，该方法被调用。成交信息包含在市场数据更新中。
     * 这些信息对于交易算法做出决策非常重要，特别是对于需要跟踪市场流动性的算法。
     * 
     * @param market_update 市场数据更新指针，包含成交信息
     * @param book 相关的订单簿指针
     * @return void
     */
    auto onTradeUpdate(const Exchange::MEMarketUpdate *market_update, MarketOrderBook *book) noexcept -> void;

    /**
     * @brief 处理订单更新
     * 
     * @details 处理客户端订单响应，更新仓位管理器并通知交易算法关于该响应。
     * 当交易所发送订单状态更新（如新建、成交、取消等）时，该方法被调用。
     * 对于成交类型的响应，还会更新仓位管理器的成交信息。
     * 
     * @param client_response 客户端订单响应指针
     * @return void
     */
    auto onOrderUpdate(const Exchange::MEClientResponse *client_response) noexcept -> void;

    /**
     * @brief 用于分发订单簿更新、成交事件和客户端响应的函数包装器
     * 
     * @details 这些函数包装器允许交易算法注册自定义的回调函数，以响应各种市场事件。
     * 在构造函数中，这些包装器初始化为默认处理函数，但交易算法可以覆盖它们以实现自定义行为。
     */
    /**
     * @brief 订单簿更新回调函数
     * 
     * @details 当订单簿发生变化时调用的函数。交易算法可以覆盖这个函数以实现自定义的订单簿更新处理。
     */
    std::function<void(TickerId ticker_id, Price price, Side side, MarketOrderBook *book)> algoOnOrderBookUpdate_;
    
    /**
     * @brief 成交事件回调函数
     * 
     * @details 当市场上发生成交时调用的函数。交易算法可以覆盖这个函数以实现自定义的成交事件处理。
     */
    std::function<void(const Exchange::MEMarketUpdate *market_update, MarketOrderBook *book)> algoOnTradeUpdate_;
    
    /**
     * @brief 订单更新回调函数
     * 
     * @details 当收到客户端订单响应时调用的函数。交易算法可以覆盖这个函数以实现自定义的订单响应处理。
     */
    std::function<void(const Exchange::MEClientResponse *client_response)> algoOnOrderUpdate_;

    /**
     * @brief 初始化最后事件时间
     * 
     * @details 将最后事件时间设置为当前时间，用于跟踪交易引擎的活动状态。
     * 这个方法通常在交易引擎初始化或重置时调用。
     * 
     * @return void
     */
    auto initLastEventTime() {
      last_event_time_ = Common::getCurrentNanos();
    }

    /**
     * @brief 获取自上次事件以来的消静时间（秒）
     * 
     * @details 计算并返回自上次事件发生以来的时间（以秒为单位）。
     * 这个方法用于监控交易引擎的活动状态，可以用来检测市场是否处于不活跃状态。
     * 
     * @return 自上次事件以来的秒数
     */
    auto silentSeconds() {
      return (Common::getCurrentNanos() - last_event_time_) / NANOS_TO_SECS;
    }

    /**
     * @brief 获取客户端标识符
     * 
     * @details 返回当前交易引擎实例的客户端标识符。
     * 客户端标识符用于区分不同的交易引擎实例，并在与交易所通信时使用。
     * 
     * @return 客户端标识符
     */
    auto clientId() const {
      return client_id_;
    }

    /**
     * @brief 删除的默认构造函数、拷贝构造函数、移动构造函数和赋值运算符
     * 
     * @details 交易引擎类不允许默认构造、拷贝或移动，以确保其安全使用。
     * 这些操作被显式删除，以防止意外创建多个交易引擎实例或意外复制。
     */
    TradeEngine() = delete;

    /**
     * @brief 删除的拷贝构造函数
     */
    TradeEngine(const TradeEngine &) = delete;

    /**
     * @brief 删除的移动构造函数
     */
    TradeEngine(const TradeEngine &&) = delete;

    /**
     * @brief 删除的拷贝赋值运算符
     */
    TradeEngine &operator=(const TradeEngine &) = delete;

    /**
     * @brief 删除的移动赋值运算符
     */
    TradeEngine &operator=(const TradeEngine &&) = delete;

  private:
    /**
     * @brief 当前交易引擎的客户端标识符
     * 
     * @details 用于唯一标识交易引擎实例，并在与交易所通信时使用。
     * 该标识符在构造函数中设置，并在整个实例生命周期内保持不变。
     */
    const ClientId client_id_;

    /**
     * @brief 从证券标识符到市场订单簿的映射容器
     * 
     * @details 存储每个交易工具的市场订单簿对象，用于跟踪市场深度和当前的买卖盘口。
     * 这些订单簿对象在构造函数中创建，并在析构函数中释放。
     */
    MarketOrderBookHashMap ticker_order_book_;

    /**
     * @brief 无锁队列
     * 
     * @details 交易引擎使用三个无锁队列进行通信：
     * 1. 用于发布出站客户端请求，由订单网关消费并发送给交易所。
     * 2. 用于消费入站客户端响应，由订单网关根据从交易所接收的数据写入。
     * 3. 用于消费入站市场数据更新，由市场数据消费者根据从交易所接收的数据写入。
     */
    /**
     * @brief 出站客户端请求队列
     * 
     * @details 用于发送订单请求到交易所的无锁队列。
     */
    Exchange::ClientRequestLFQueue *outgoing_ogw_requests_ = nullptr;
    
    /**
     * @brief 入站客户端响应队列
     * 
     * @details 用于接收来自交易所的订单响应的无锁队列。
     */
    Exchange::ClientResponseLFQueue *incoming_ogw_responses_ = nullptr;
    
    /**
     * @brief 入站市场数据更新队列
     * 
     * @details 用于接收来自交易所的市场数据更新的无锁队列。
     */
    Exchange::MEMarketUpdateLFQueue *incoming_md_updates_ = nullptr;

    /**
     * @brief 最后事件时间（纺秒）
     * 
     * @details 记录最后一次处理事件（订单响应或市场数据更新）的时间。
     * 用于计算交易引擎的活动状态和检测市场是否处于不活跃状态。
     */
    Nanos last_event_time_ = 0;
    
    /**
     * @brief 运行标志
     * 
     * @details 控制交易引擎主循环是否继续运行的标志。
     * 在启动方法中设置为真，在停止方法中设置为假。
     * 声明为volatile以确保在多线程环境中的可见性。
     */
    volatile bool run_ = false;

    /**
     * @brief 时间字符串缓存
     * 
     * @details 用于在日志记录中存储当前时间的字符串表示，避免重复创建。
     */
    std::string time_str_;
    
    /**
     * @brief 日志记录器
     * 
     * @details 用于记录交易引擎的操作和状态的日志记录器。
     * 在构造函数中初始化，使用客户端标识符作为日志文件名的一部分。
     */
    Logger logger_;

    /**
     * @brief 交易算法的特征引擎
     * 
     * @details 特征引擎负责计算和维护各种市场特征，如价格趋势、波动率、成交量等，
     * 为交易算法提供决策依据。它在订单簿变化和成交事件发生时被更新。
     */
    FeatureEngine feature_engine_;

    /**
     * @brief 仓位管理器，用于跟踪仓位、盈亏和交易量
     * 
     * @details 仓位管理器负责跟踪每个交易工具的仓位、盈亏和交易量。
     * 当收到成交响应或最优价格（BBO）变化时，仓位管理器会更新相应的信息。
     */
    PositionKeeper position_keeper_;

    /**
     * @brief 订单管理器，简化交易算法的订单管理任务
     * 
     * @details 订单管理器提供了一组方便的接口，简化交易算法发送和管理订单的过程。
     * 它处理订单创建、取消和跟踪，并在发送订单前进行风险检查。
     */
    OrderManager order_manager_;

    /**
     * @brief 风险管理器，跟踪并执行交易前风险检查
     * 
     * @details 风险管理器负责对每个交易工具进行交易前的风险检查，如订单大小、仓位大小和损失限制。
     * 它与仓位管理器密切协作，确保交易在安全的风险参数范围内进行。
     */
    RiskManager risk_manager_;

    /**
     * @brief 做市商或流动性接受者算法实例
     * 
     * @details 在一个交易引擎实例中，只创建这两种算法中的一种。
     * 算法类型由构造函数中的algo_type参数决定。
     */
    /**
     * @brief 做市商算法实例
     * 
     * @details 当algo_type为MAKER时创建的做市商算法实例。
     * 做市商算法通过提供流动性赚取买卖差价。
     */
    MarketMaker *mm_algo_ = nullptr;
    
    /**
     * @brief 流动性接受者算法实例
     * 
     * @details 当algo_type为TAKER时创建的流动性接受者算法实例。
     * 流动性接受者算法通过主动匹配市场上的订单来执行交易策略。
     */
    LiquidityTaker *taker_algo_ = nullptr;

    /**
     * @brief 默认方法用于初始化函数包装器
     * 
     * @details 这些默认方法在构造函数中用于初始化函数包装器，如果交易算法没有覆盖这些回调，
     * 则使用这些默认方法。它们仅记录日志，不执行任何实际的交易操作。
     */
    
    /**
     * @brief 默认的订单簿更新处理方法
     * 
     * @details 当订单簿发生变化时的默认处理方法，仅记录日志信息。
     * 记录证券标识符、价格和侧向信息。
     * 
     * @param ticker_id 证券标识符
     * @param price 变化的价格
     * @param side 变化的侧向（买入或卖出）
     * @param book 变化的订单簿指针（未使用）
     * @return void
     */
    auto defaultAlgoOnOrderBookUpdate(TickerId ticker_id, Price price, Side side, MarketOrderBook *) noexcept -> void {
      logger_.log("%:% %() % ticker:% price:% side:%\n", __FILE__, __LINE__, __FUNCTION__,
                  Common::getCurrentTimeStr(&time_str_), ticker_id, Common::priceToString(price).c_str(),
                  Common::sideToString(side).c_str());
    }

    /**
     * @brief 默认的成交事件处理方法
     * 
     * @details 当市场上发生成交时的默认处理方法，仅记录日志信息。
     * 记录市场数据更新的字符串表示。
     * 
     * @param market_update 市场数据更新指针，包含成交信息
     * @param book 相关的订单簿指针（未使用）
     * @return void
     */
    auto defaultAlgoOnTradeUpdate(const Exchange::MEMarketUpdate *market_update, MarketOrderBook *) noexcept -> void {
      logger_.log("%:% %() % %\n", __FILE__, __LINE__, __FUNCTION__, Common::getCurrentTimeStr(&time_str_),
                  market_update->toString().c_str());
    }

    /**
     * @brief 默认的订单更新处理方法
     * 
     * @details 当收到客户端订单响应时的默认处理方法，仅记录日志信息。
     * 记录客户端响应的字符串表示。
     * 
     * @param client_response 客户端订单响应指针
     * @return void
     */
    auto defaultAlgoOnOrderUpdate(const Exchange::MEClientResponse *client_response) noexcept -> void {
      logger_.log("%:% %() % %\n", __FILE__, __LINE__, __FUNCTION__, Common::getCurrentTimeStr(&time_str_),
                  client_response->toString().c_str());
    }
  };
}
